#pragma once
#include"data.hpp"
#include"httplib.h"
#include<algorithm>
extern cloud::DataManger* _data;
namespace cloud
{
    class Server{

    public:
    Server(){
        Config* config=Config::GetInstance();
        _server_port= config->GetServerPort();
        _server_ip=config->GetServerIp();
        _download_prefix=config->GetDownloadPrefix();
    };
    bool RunModule(){
      
        _server.Post("/upload",Upload);
        _server.Get("/listshow",ListShow);
         _server.Get("/",ListShow);
        std::string download_url=_download_prefix+"(.*)";
        _server.Get(download_url,Download);
        _server.listen(_server_ip.c_str(),_server_port);
        return true;
    }

    
    private:
    
    //上传文件
    static void Upload(const httplib::Request&req,httplib::Response&rsp)
    {
        auto ret=req.has_file("file");//判断有没有上传的文件区域
        if(ret==false)
        {
            rsp.status=400;
            return ;
        }

        const auto &file=req.get_file_value("file");
        //file.filename//文件名称  file.content//文件数据
        std::string back_dir=Config::GetInstance()->GetBackDir();
        std::string realpath=back_dir+FileUtil(file.filename).FileName();
        FileUtil fu(realpath);
        fu.SetContent(file.content);//将数据写入文件中
        BackupInfo info;
        info.NewBackupInfo(realpath);//组织备份的文件信息
        _data->Insert(info);//向数据管理模块添加备份的文件信息
        return ;

    }
    static std::string TimetoStr(time_t t){
        std::string temp=std::ctime(&t);
        int i=0;
        while(i<temp.size())
        {
            int j=i;
            while(j<temp.size()&&temp[j]!=' ')
            {
               j++;
            }
            std::reverse(temp.begin()+i,temp.begin()+j);
            i=j+1;
        }
        std::reverse(temp.begin(),temp.end());
        return temp;

    }
    //展示页面
    static void ListShow(const httplib::Request&req,httplib::Response&rsp){
        //1.获取所有的文件备份信息
          std::vector<BackupInfo> arry;
          _data->GetAll(&arry);
       
       //2.根据文件信息组织html文件数据
          std::stringstream ss;
          ss<< "<html><head><title>Download</title></head>";
          ss<< "<body><h1>Download</h1><table>";
          for(auto &a:arry)
          {
            ss<<"<tr>";
            std::string filename=FileUtil(a._realpath).FileName();
            ss<< "<td><a href='" << a._url << "'>" <<filename<< "</a></td>";
            ss<< "<td align='right'>" << TimetoStr(a._mtime) << "</td>";
            ss<< "<td align='right'>" << a._fsize/1024 << "k</td>";
            ss<< "</tr>";
          }
          ss<< "</table></boay></html>";
          rsp.body=ss.str();
          rsp.set_header("Content-Type","text/html");
          rsp.status=200;
          return ;

    }
   static std::string GetETag( BackupInfo&info){
        //etg标识：filename-fsize-mtime
        FileUtil fu(info._realpath);
        std::string etag=fu.FileName();
        etag+="-";
        etag+=std::to_string(info._fsize);
        etag+="-";
        etag+=std::to_string(info._mtime);
        return etag;
    }
    static void Download(const httplib::Request&req,httplib::Response&rsp){
           //1.获取客户端请求的资源路径path 
           //2.根据资源路径，获取文件备份信息
            BackupInfo info;
           _data->GetOneByURL(req.path,&info);
           //3.判断文件是否被压缩，如果被压缩要先解压
           if(info._packflag==true)
           {
              FileUtil fu(info._packpath);
              fu.UnCompress(info._realpath);
            //4.删除压缩包，修改备份信息(已经没有被压缩)
             fu.Remove();
             info._packflag=false;
            _data->Update(info);
           }
            
            //5.读取文件数据，放入rsq.body;
            FileUtil fu(info._realpath);
           bool retans=false;
           std::string old_etag;
           if(req.has_header("If-Range"))
           {
               old_etag=req.get_header_value("If-Range");
               if(old_etag==GetETag(info)){

                   retans=true;
               }
           }
             
           if(retans==false)
           {   
              fu.GetContent(rsp.body);
              // 6.设置响应头部字段:ETag Avvept-Ranges:Bytes
               rsp.set_header("Accept-Ranges", "bytes");
               rsp.set_header("ETag", GetETag(info));
               rsp.set_header("Content-Type", "application/octet-stream");
               rsp.status = 200;
           }
           else
           { 
            //httplib 内部实现了对于区间请求也就是断点续传的请求处理
             fu.GetContent(rsp.body);
             rsp.set_header("Accept-Ranges","bytes");
             rsp.set_header("ETag",GetETag(info));
             rsp.status=206;

           }
    }
    private:
    int _server_port;
    std::string _server_ip;
    std::string _download_prefix;
    httplib::Server _server;

    };
}

